/*
* Copyright (c) 2025 OpenHarmonyPCDeveloper
* Licensed under the Mulan PSL v2 (the "License");
*/

#include "napi/native_api.h"
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <iostream>
#include <numeric>
#include <set>
#include <vector>
#include <algorithm>
#include <sstream>
#include <stdio.h>
#include <regex>
#include <hilog/log.h>
#include <unistd.h>
#include <thread>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h> 
#include <unistd.h> 
#include <errno.h>
#include <string.h>


static int g_bufferSize = 4096;

struct CallbackData {
    napi_async_work asyncWork = nullptr;
    napi_ref callbackRef = nullptr;
    std::string args[2];
    std::string result;
    std::vector<uint8_t> result_buf;
    napi_env env;
    napi_threadsafe_function safe_func;
};

static void CallJs(napi_env env, napi_value jsCallback, void *context, void *data)
{
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    
    std::string* msg = static_cast<std::string*>(data);
    napi_value argv;
    napi_create_string_utf8(env, msg->c_str(), NAPI_AUTO_LENGTH, &argv);

    napi_value result;
    napi_call_function(env, undefined, jsCallback, 1, &argv, &result);
    
    delete msg;
}

static int ExecCmd(const std::string &cmdStr, const std::string &pathStr,
                    std::function<void(const std::string &)> callback)
{

    if (!pathStr.empty() && (chdir(pathStr.c_str()) != 0)) {
        std::cerr << "[ExecCmd] chdir failed: " << pathStr << std::endl;
        return 1;
    }

    FILE *fp = popen(cmdStr.c_str(), "r");
    if (!fp) {
        return 1;
    }

    char buffer[1024] = {0};

    // Flag to track if empty line has been sent
    bool sentEmptyLine = false;

    while (fgets(buffer, sizeof(buffer), fp) != nullptr) {
        std::string line(buffer);

        // Check if the line is empty and not yet sent
        if (line == "\n" && !sentEmptyLine) {
            callback(line);
            // Mark empty line as sent
            sentEmptyLine = true;
        } else if (line != "\n") {
            // Send non-empty lines
            callback(line);
        }
    }

    pclose(fp);

    // Send EOF marker after reading all lines
    callback("[EOF]");

    return 0;
}

static int ExecCmd(const std::string &cmdStr, const std::string &pathStr, std::string &output)
{
    if (!pathStr.empty() && (chdir(pathStr.c_str()) != 0)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[ExecCmd] chdir failed!");
        return 1;
    }
    
    std::string cmd = cmdStr + " 2>&1";
    FILE *fp = popen(cmd.c_str(), "r");
    if (!fp) {
        return 1;
    }

    std::vector<char> buf(g_bufferSize);
    output.clear();

    size_t bytesRead;
    while ((bytesRead = fread(buf.data(), 1, buf.size(), fp)) > 0) {
        output.append(buf.data(), bytesRead);
    }

    int exitStatus = pclose(fp);
    if (exitStatus == -1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 3, "GitNext", "[ExecCmd] pclose failed");
        return 1;
    }
    
    int exitCode = WEXITSTATUS(exitStatus);
    if(exitCode != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 3, "GitNext", "[ExecCmd] Command failed: exit code %{public}d, output: %{public}s\n",
            exitCode, output.c_str());
        return 1;
    }
    
    return 0;
}

static int ExecCmd(const std::string &cmdStr, const std::string &pathStr, std::vector<uint8_t> &output)
{
    if (!pathStr.empty() && (chdir(pathStr.c_str()) != 0)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[ExecCmd] chdir failed!");
        return 1;
    }

    FILE *fp = popen(cmdStr.c_str(), "r");
    if (!fp) {
        return 1;
    }

    std::vector<uint8_t> buf(g_bufferSize);
    output.clear();

    size_t bytesRead;
    while ((bytesRead = fread(buf.data(), 1, buf.size(), fp)) > 0) {
        output.insert(output.end(), buf.begin(), buf.begin() + bytesRead);
    }

    pclose(fp);
    return 0;
}

static void create_array_buffer(napi_env env, std::vector<uint8_t> &data, napi_value *result)
{
    napi_value output_buffer;
    void *outputPtr = nullptr;
    napi_create_arraybuffer(env, data.size() * sizeof(uint8_t), &outputPtr, &output_buffer);
    napi_create_typedarray(env, napi_uint8_array, data.size(), output_buffer, 0, result);

    uint8_t *outputBytes = (uint8_t *)outputPtr;
    std::copy(data.begin(), data.end(), outputBytes);
}

static void SysCallByLineCompleteCB(napi_env env, napi_status status, void *data)
{
    CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);

    napi_release_threadsafe_function(callbackData->safe_func, napi_tsfn_release);
    napi_delete_reference(env, callbackData->callbackRef);
    napi_delete_async_work(env, callbackData->asyncWork);
    delete callbackData;
}

static void SysCallBufExecuteCB(napi_env env, void *data)
{
    CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
    ExecCmd(callbackData->args[0], callbackData->args[1], callbackData->result_buf);
}

static void SysCallBufCompleteCB(napi_env env, napi_status status, void *data)
{
    CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
    napi_value callbackArg[1] = {nullptr};
    create_array_buffer(env, callbackData->result_buf, &callbackArg[0]);

    napi_value callback = nullptr;
    napi_get_reference_value(env, callbackData->callbackRef, &callback);

    napi_value result;
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    napi_call_function(env, undefined, callback, 1, callbackArg, &result);

    napi_delete_reference(env, callbackData->callbackRef);
    napi_delete_async_work(env, callbackData->asyncWork);
    delete callbackData;
}

static void SysCallExecuteCB(napi_env env, void *data)
{
    CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
    ExecCmd(callbackData->args[0], callbackData->args[1], callbackData->result);
}

static void SysCallCompleteCB(napi_env env, napi_status status, void *data)
{
    CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);
    napi_value callbackArg[1] = {nullptr};
    napi_create_string_utf8(env, callbackData->result.c_str(), callbackData->result.length(), &callbackArg[0]);
    napi_value callback = nullptr;
    napi_get_reference_value(env, callbackData->callbackRef, &callback);

    napi_value result;
    napi_value undefined;
    napi_get_undefined(env, &undefined);
    napi_call_function(env, undefined, callback, 1, callbackArg, &result);

    napi_delete_reference(env, callbackData->callbackRef);
    napi_delete_async_work(env, callbackData->asyncWork);
    delete callbackData;
}

static napi_value SysCallSync(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    char cmd[2048] = {0};
    size_t cmd_size = 0;
    memset(cmd, 0, sizeof(cmd));
    if (napi_ok != napi_get_value_string_utf8(env, args[0], cmd, sizeof(cmd), &cmd_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallSync] get cmd failed");
        return nullptr;
    }

    char path[1024] = {0};
    size_t path_size = 0;
    memset(path, 0, sizeof(path));
    if (napi_ok != napi_get_value_string_utf8(env, args[1], path, sizeof(path), &path_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallSync] get path failed");
        return nullptr;
    }

    std::string output;
    ExecCmd(std::string(cmd), std::string(path), output);

    napi_value result;
    napi_create_string_utf8(env, output.c_str(), output.length(), &result);

    return result;
}

static napi_value SysCallAsync(napi_env env, napi_callback_info info)
{
    size_t argc = 3;
    napi_value args[3];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    auto asyncContext = new CallbackData();

    char cmd[2048] = {0};
    size_t cmd_size = 0;
    memset(cmd, 0, sizeof(cmd));
    if (napi_ok != napi_get_value_string_utf8(env, args[0], cmd, sizeof(cmd), &cmd_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCall] get cmd failed");
        delete asyncContext;
        return nullptr;
    }

    char path[1024] = {0};
    size_t path_size = 0;
    memset(path, 0, sizeof(path));
    if (napi_ok != napi_get_value_string_utf8(env, args[1], path, sizeof(path), &path_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCall] get path failed");
        delete asyncContext;
        return nullptr;
    }

    asyncContext->args[0] = std::string(cmd);
    asyncContext->args[1] = std::string(path);

    napi_create_reference(env, args[2], 1, &asyncContext->callbackRef);
    napi_value resourceName = nullptr;
    napi_create_string_utf8(env, "asyncWorkCallback", NAPI_AUTO_LENGTH, &resourceName);

    napi_create_async_work(env, nullptr, resourceName, SysCallExecuteCB, SysCallCompleteCB, asyncContext,
                           &asyncContext->asyncWork);

    napi_queue_async_work(env, asyncContext->asyncWork);
    return nullptr;
}

static napi_value SysCallBuf(napi_env env, napi_callback_info info)
{
    size_t argc = 3;
    napi_value args[3];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    auto asyncContext = new CallbackData();

    char cmd[2048] = {0};
    size_t cmd_size = 0;
    memset(cmd, 0, sizeof(cmd));
    if (napi_ok != napi_get_value_string_utf8(env, args[0], cmd, sizeof(cmd), &cmd_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallBuf] get cmd failed");
        delete asyncContext;
        return nullptr;
    }

    char path[1024] = {0};
    size_t path_size = 0;
    memset(path, 0, sizeof(path));
    if (napi_ok != napi_get_value_string_utf8(env, args[1], path, sizeof(path), &path_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallBuf] get path failed");
        delete asyncContext;
        return nullptr;
    }

    asyncContext->args[0] = std::string(cmd);
    asyncContext->args[1] = std::string(path);

    napi_create_reference(env, args[2], 1, &asyncContext->callbackRef);
    napi_value resourceName = nullptr;
    napi_create_string_utf8(env, "asyncWorkCallback", NAPI_AUTO_LENGTH, &resourceName);

    napi_create_async_work(env, nullptr, resourceName, SysCallBufExecuteCB, SysCallBufCompleteCB, asyncContext,
                           &asyncContext->asyncWork);

    napi_queue_async_work(env, asyncContext->asyncWork);
    return nullptr;
}

static void SysCallByLineExecCB(napi_env env, void *data)
{
    CallbackData *callbackData = reinterpret_cast<CallbackData *>(data);

    auto line_callback = [callbackData](const std::string &line) {
        napi_call_threadsafe_function(callbackData->safe_func, new std::string(line), napi_tsfn_blocking);
    };

    ExecCmd(callbackData->args[0], callbackData->args[1], line_callback);
}

static void FreeDataCb(napi_env env, void *data, void* hint)
{
    if(data != nullptr) {
        std::string* str = static_cast<std::string*>(data);
        delete str;
    }
}

static napi_value SysCallByLine(napi_env env, napi_callback_info info) {
    size_t argc = 3;
    napi_value args[3];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    auto asyncContext = new CallbackData();

    char cmd[2048] = {0};
    size_t cmd_size = 0;
    memset(cmd, 0, sizeof(cmd));
    if (napi_ok != napi_get_value_string_utf8(env, args[0], cmd, sizeof(cmd), &cmd_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallByLine] get cmd failed");
        delete asyncContext;
        return nullptr;
    }

    char path[1024] = {0};
    size_t path_size = 0;
    memset(path, 0, sizeof(path));
    if (napi_ok != napi_get_value_string_utf8(env, args[1], path, sizeof(path), &path_size)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallByLine] get path failed");
        delete asyncContext;
        return nullptr;
    }

    asyncContext->args[0] = std::string(cmd);
    asyncContext->args[1] = std::string(path);
    asyncContext->env = env;

    napi_create_reference(env, args[2], 1, &asyncContext->callbackRef);

    napi_value resourceName;
    napi_create_string_utf8(env, "asyncWorkCallback", NAPI_AUTO_LENGTH, &resourceName);

    napi_create_threadsafe_function(env, args[2], nullptr, resourceName, 0, 1, nullptr, FreeDataCb,
        nullptr, CallJs, &asyncContext->safe_func);
    napi_create_async_work(env, nullptr, resourceName, SysCallByLineExecCB, SysCallByLineCompleteCB, asyncContext,
                           &asyncContext->asyncWork);
    napi_queue_async_work(env, asyncContext->asyncWork);

    return nullptr;
}

static napi_value SetConfigEnv(napi_env env, napi_callback_info info)
{
    const char *env_name = "HOME";
    const char *env_value = "/storage/Users/currentUser";
    
    if (setenv(env_name, env_value, 1) != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "Error setting environment variable");
        return nullptr;
    }
    return nullptr;
}

static napi_value Chmod(napi_env env, napi_callback_info info)
{
    mode_t permissions = 0770;
    // 保证目录存在
    std::string configPath = "/storage/Users/currentUser/.ohos_git/.gitconfig";
    std::string configDir = "/storage/Users/currentUser/.ohos_git";

    // 创建目录（如果不存在）
    struct stat st = {0};
    if (stat(configDir.c_str(), &st) == -1) {
        if (mkdir(configDir.c_str(), permissions) != 0) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "无法创建目录: /storage/Users/currentUser/.ohos_git");
        }
    }

    // 创建文件（如果不存在）
    int fd = open(configPath.c_str(), O_CREAT | O_RDWR, permissions);
    if (fd == -1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "无法打开或创建文件: /storage/Users/currentUser/.ohos_git/.gitconfig");
    }
    close(fd);
    
    int result = chmod("/storage/Users/currentUser/.ohos_git/.gitconfig", permissions);
    if(result != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "Chmod to 770 failed: %{public}s", strerror(errno));
    }
    return nullptr;
}

static std::string GitInitConfig()
{
    std::string result = "";
    std::string cmd = "git config --global --list";
    std::string output = "";
    int ret = ExecCmd(cmd.c_str(), "", output);
    if(ret != 0) {
        return result;
    }
    
    std::vector<std::string> lines;
    std::istringstream iss(output);
    std::string line = "";
    while (std::getline(iss, line)) {
        line = line.substr(0, line.find_last_not_of(" \t\n\r") + 1);
        if (!line.empty()) {
            lines.push_back(line);
        }
    }
    
    // 检查是否已设置 safe.directory=*
    bool hasSafeDirectory = std::any_of(lines.begin(), lines.end(),
        [](const std::string& config) { return config == "safe.directory=*"; });
    
    if (!hasSafeDirectory) {
        std::string addCmd = "git config --global --add safe.directory \"*\"";
        ret = ExecCmd(addCmd.c_str(), "", output);
        if (ret == 0) {
            lines.push_back("safe.directory=*");
        }
    }
    
    // 设置 core.quotepath
    std::string quotepathCmd = "git config --global core.quotepath false";
    ret = ExecCmd(quotepathCmd.c_str(), "", output);
    if (ret == 0) {
        auto it = std::find_if(lines.begin(), lines.end(), [](const std::string& config){
            return config.find("core.quotepath") == 0;
        });
        if (it == lines.end()) {
            lines.push_back("core.quotepath=false");
        } else {
            *it = "core.quotepath=false";
        }
    }
    
    // 设置 credential.helper
    std::string credCmd = "git config --global credential.helper store";
    ret = ExecCmd(credCmd.c_str(), "", output);
    if (ret == 0) {
        auto it = std::find_if(lines.begin(), lines.end(), [](const std::string& config){
            return config.find("credential.helper") == 0;
        });
        if (it == lines.end()) {
            lines.push_back("credential.helper=store");
        } else {
            *it = "credential.helper=store";
        }
    }
    
    // 重新获取配置列表
    cmd = "git config --global --list";
    output.clear();
    ret = ExecCmd(cmd.c_str(), "", output);
    if(ret != 0) {
        return result;
    }
    
    // 处理最终输出
    std::istringstream finalIss(output);
    while (std::getline(finalIss, line)) {
        line = line.substr(0, line.find_last_not_of(" \t\n\r") + 1);
        if(!line.empty()) {
            if(!result.empty()) {
                result += "\n";
            }
            result += line;
        }
    }
    
    return result;
}

static napi_value SysCallInitConfigSync(napi_env env, napi_callback_info info)
{
    size_t argc = 0;
    napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);
    
    try {
        std::string configs = GitInitConfig();
        
        napi_value ret;
        napi_status status = napi_create_string_utf8(env, configs.c_str(), configs.length(), &ret);
        if (status != napi_ok) {
            return nullptr;
        }
        return ret;
    } catch (const std::exception& e) {
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    } catch (...) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitInitConfigSync] Unknown exception occurred");
        napi_value error;
        napi_create_string_utf8(env, "Unknown error in GitInitConfigSync", NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }
}

struct FileStatus {
    std::string status; // 状态码 A M D U
    std::string path; // 文件路径
};

static void ScanUntrackedDirectory(const std::string& repoPath,
    const std::string& dirPath, std::vector<FileStatus>& unstaged)
{
    std::string cmd = "git ls-files --others --exclude-standard -z \"" + dirPath + "\"";
    
    std::string output = "";
    int ret = ExecCmd(cmd, repoPath, output);
    if (ret != 0 || output.empty()) {
        OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[ScanUntrackedDirectory] Failed to exec cmd");
        return;
    }

    size_t start = 0;
    while (start < output.length()) {
        size_t end = output.find('\0', start);
        if (end == std::string::npos) {
            if (start < output.length()) {
                std::string filePath = output.substr(start);
                if (!filePath.empty()) {
                    unstaged.push_back({"A", filePath});
                }
            }
            break;
        }
        std::string filePath = output.substr(start, end - start);
        if (!filePath.empty()) {
            unstaged.push_back({"A", filePath});
        }
        start = end + 1;
    }
}

static void ParseGitStatus(const std::string& repoPath, const std::string& cmd,
    std::vector<FileStatus>& staged, std::vector<FileStatus>& unstaged)
{
    auto callback = [&](const std::string& line) {
        if (line == "[EOF]") {
            return;
        }

        std::string trimmed = line;
        if (!trimmed.empty() && trimmed.back() == '\n') {
            trimmed.pop_back();
        }
        if(trimmed.empty()) {
            return;
        }
        if(trimmed.length() < 4) {
            return;
        }

        std::string status = trimmed.substr(0, 2);
        std::string path = trimmed.substr(3);

        if(status == "??" && (path.back() == '/' || path.back() == '\\')) {     // 处理未跟踪目录
            ScanUntrackedDirectory(repoPath, path, unstaged);
            return;
        }

        if (status == "R " || status == "C ") {   // 处理重命名和复制操作
            size_t arrowPos = path.find(" -> ");
            if (arrowPos != std::string::npos) {
                std::string oldPath = path.substr(0, arrowPos);
                std::string newPath = path.substr(arrowPos + 4);
                if (status == "R ") {
                    staged.push_back({"D", oldPath});
                }
                staged.push_back({"A", newPath});
                return;
            }
        }

        if (status == "AA" || status == "AU" || status == "UA" || status == "DD" ||
            status == "DU" || status == "UD" || status == "UU") {
            unstaged.push_back({"U", path});
            return;
        }

        if (status[0] != ' ' && status[0] != '?' && status[0] != '!') {    // 处理暂存区状态
            bool exists = false;
            for (const auto& s : staged) {
                if (s.path == path) {
                    exists = true;
                    break;
                }
            }
            if (!exists) {
                staged.push_back({std::string(1, status[0]), path});
            }
        }

        if(status[1] != ' ' && status[1] != '?' && status[1] != '!') {    // 处理工作区状态
            bool exists = false;
            for (const auto& u : unstaged) {
                if (u.path == path) {
                    exists = true;
                    break;
                }
            }
            if (!exists) {
                unstaged.push_back({std::string(1, status[1]), path});
            }
        }

        if (status == "??") {
            unstaged.push_back({"A", path});
        }
    };

    int ret = ExecCmd(cmd, repoPath, callback);
    if (ret != 0){
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[ParseGitStatus] Failed to exec cmd");
    }
}

static void GitRescan(const std::string& repoPath, std::vector<FileStatus>& staged, std::vector<FileStatus>& unstaged)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitRescan] repoPath is empty");
        return;
    }
    
    staged.clear();
    unstaged.clear();

    try {
        std::string cmd = "git status --porcelain --untracked-files=all";
        ParseGitStatus(repoPath, cmd, staged, unstaged);
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitRescan] Exception: %{public}s", e.what());
    }

    auto sortFileStatus = [](const FileStatus& a, const FileStatus& b) -> bool {
        return a.path < b.path;
    };

    std::sort(staged.begin(), staged.end(), sortFileStatus);
    std::sort(unstaged.begin(), unstaged.end(), sortFileStatus);
}

static napi_value SysCallReScanSync(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    char path[1024] = {0};
    size_t pathSize = 0;
    if (napi_ok != napi_get_value_string_utf8(env, argv[0], path, sizeof(path), &pathSize)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallReScanSync] get path failed");
        return nullptr;
    }

    std::vector<FileStatus> staged;
    std::vector<FileStatus> unstaged;

    try {
        GitRescan(std::string(path), staged, unstaged);
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallReScanSync] Exception: %{public}s", e.what());
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }

    // 构建返回对象：{staged: [], unstaged: []}
    napi_value resultObj;
    napi_create_object(env, &resultObj);

    // 构造 staged 数组
    napi_value stagedArray;
    napi_create_array_with_length(env, staged.size(), &stagedArray);
    for (size_t i = 0; i < staged.size(); ++i) {
        napi_value item;
        napi_create_object(env, &item);

        napi_value pathKey;
        napi_create_string_utf8(env, "path", NAPI_AUTO_LENGTH, &pathKey);
        napi_value pathValue;
        napi_create_string_utf8(env, staged[i].path.c_str(), NAPI_AUTO_LENGTH, &pathValue);
        napi_set_property(env, item, pathKey, pathValue);

        napi_value statusKey;
        napi_create_string_utf8(env, "status", NAPI_AUTO_LENGTH, &statusKey);
        napi_value statusValue;
        napi_create_string_utf8(env, staged[i].status.c_str(), NAPI_AUTO_LENGTH, &statusValue);
        napi_set_property(env, item, statusKey, statusValue);

        napi_set_element(env, stagedArray, i, item);
    }
    napi_value stagedKey;
    napi_create_string_utf8(env, "staged", NAPI_AUTO_LENGTH, &stagedKey);
    napi_set_property(env, resultObj, stagedKey, stagedArray);

    // 构造 unstaged 数组
    napi_value unstagedArray;
    napi_create_array_with_length(env, unstaged.size(), &unstagedArray);
    for (size_t i = 0; i < unstaged.size(); ++i) {
        napi_value item;
        napi_create_object(env, &item);

        napi_value pathKey;
        napi_create_string_utf8(env, "path", NAPI_AUTO_LENGTH, &pathKey);
        napi_value pathValue;
        napi_create_string_utf8(env, unstaged[i].path.c_str(), NAPI_AUTO_LENGTH, &pathValue);
        napi_set_property(env, item, pathKey, pathValue);

        napi_value statusKey;
        napi_create_string_utf8(env, "status", NAPI_AUTO_LENGTH, &statusKey);
        napi_value statusValue;
        napi_create_string_utf8(env, unstaged[i].status.c_str(), NAPI_AUTO_LENGTH, &statusValue);
        napi_set_property(env, item, statusKey, statusValue);

        napi_set_element(env, unstagedArray, i, item);
    }
    napi_value unstagedKey;
    napi_create_string_utf8(env, "unstaged", NAPI_AUTO_LENGTH, &unstagedKey);
    napi_set_property(env, resultObj, unstagedKey, unstagedArray);

    return resultObj;
}

static std::string TryAddWithRetry(const std::string& repoPath, const std::string& filePath, int maxRetries = 2)
{
    std::string addCmd = "git add " + filePath;
    std::string output;
    int attempt = 0;

    while (attempt <= maxRetries) {
        ++attempt;
        int ret = ExecCmd(addCmd, repoPath, output);
        if (ret == 0) {
            return "";
        }
        if (output.find("index.lock") != std::string::npos) {
            const std::string lockPath = repoPath + "/.git/index.lock";
            std::string removeLockCmd = "rm -f " + lockPath;
            ExecCmd(removeLockCmd, repoPath, output);
        }

        if (attempt < maxRetries + 1) {
            int delayMs = 50 * (1 << attempt);
            std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
        }
    }
    
    // 返回错误信息
    return "failed to add '" + filePath + "' error: " + output;
}

static std::string GitAdd(const std::string& repoPath, const std::vector<std::string>& fileList)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitAdd] repoPath is empty");
        return "repository path is empty";
    }

    if (fileList.empty()) {
        OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitAdd] fileList is empty");
        return "file list is empty";
    }

    std::string errorMessages;
    bool hasErrors = false;

    for (const std::string& filePath : fileList) {
        if (filePath.empty()) {
            OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitAdd] filePath is empty");
            errorMessages += "empty file path in list\n";
            hasErrors = true;
            continue;
        }
        
        std::string result = TryAddWithRetry(repoPath, filePath, 2);
        if (!result.empty()) {
            errorMessages += result + "\n";
            hasErrors = true;
        }
    }
    
    if (hasErrors) {
        return errorMessages;
    }
    
    return ""; // 成功返回空字符串
}

static napi_value SysCallAddSync(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    char path[1024] = {0};
    size_t pathLen = 1024;
    if (napi_ok != napi_get_value_string_utf8(env, args[0], path, sizeof(path), &pathLen)) {
        return nullptr;
    }

    napi_value fileListArg = args[1];
    uint32_t fileListLength = 0;
    if (napi_ok != napi_get_array_length(env, fileListArg, &fileListLength)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallAddSync] get path failed");
        return nullptr;
    }

    std::vector<std::string> fileList;
    fileList.reserve(fileListLength);

    for (uint32_t i = 0; i < fileListLength; ++i) {
        napi_value item;
        if(napi_ok != napi_get_element(env, fileListArg, i, &item)) {
            continue;
        }
        char filePath[1024] = {0};
        size_t filePathLen = 1024;
        if (napi_ok != napi_get_value_string_utf8(env, item, filePath, sizeof(filePath), &filePathLen)) {
            continue;
        }
        fileList.emplace_back(filePath);
    }

    std::string result;
    try {
        result = GitAdd(std::string(path), fileList);
    } catch (std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallAddSync] %{public}s", e.what());
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }

    // 创建并返回结果字符串
    napi_value resultValue;
    if (napi_ok != napi_create_string_utf8(env, result.c_str(), result.length(), &resultValue)) {
        return nullptr;
    }

    return resultValue;
}

static std::string GitCommit(const std::string& repoPath, const std::string& commitMessage,
    const std::string& signOffMessage, bool isSignOff = false, bool isAmend = false)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitCommit] repoPath is empty");
        return "repoPath is empty";
    }

    if (commitMessage.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitCommit] commit message is empty");
        return "commit message is empty";
    }

    // 获取状态：检查是否有变更
    std::string statusCmd = "git status --porcelain";
    std::string output;
    int ret = ExecCmd(statusCmd, repoPath, output);
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitCommit] git status failed: %{public}s", output.c_str());
        return "failed to get git status";
    }

    if (output.empty()) {
        OH_LOG_Print(LOG_APP, LOG_INFO, 1, "GitNext", "[GitCommit] nothing to commit");
        return "nothing to commit";
    }

    // 构建提交消息
    std::string finalMessage = commitMessage;
    if (isSignOff && !signOffMessage.empty()) {
        finalMessage += "\n\n" + signOffMessage;
    }

    // 构建 commit 命令
    std::string commitCmd = "";
    if (isAmend) {
        commitCmd = "git commit --amend --quiet --no-edit -m '" + finalMessage + "'";
    } else {
        commitCmd = "git commit --quiet -m '" + finalMessage + "'";
    }

    // 执行 commit 命令
    output.clear();
    ret = ExecCmd(commitCmd, repoPath, output);
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitCommit] git commit failed: %{public}s", output.c_str());
        return output;
    }

    bool isCommitFailed = false;
    std::string lowerOutput = output;
    std::transform(lowerOutput.begin(), lowerOutput.end(), lowerOutput.begin(), ::tolower);
    
    // 定义更精确的错误匹配规则（支持多行、首行错误、上下文敏感）
    std::vector<std::regex> failurePatterns = {
        std::regex(R"(^error:\s.*)", std::regex_constants::icase),
        std::regex(R"(^fatal:\s.*)", std::regex_constants::icase),
        std::regex(R"(conflict\s*\(.+\))", std::regex_constants::icase),
        std::regex(R"(merge conflict)", std::regex_constants::icase),
        std::regex(R"(would be overwritten)", std::regex_constants::icase),
        std::regex(R"(cannot commit)", std::regex_constants::icase),
        std::regex(R"(not staged for commit)", std::regex_constants::icase),
        std::regex(R"(already exists)", std::regex_constants::icase),
        std::regex(R"(needs merge)", std::regex_constants::icase),
        std::regex(R"(unmerged paths)", std::regex_constants::icase),
        std::regex(R"(dirty work tree)", std::regex_constants::icase),
        std::regex(R"(lock file)", std::regex_constants::icase),
        std::regex(R"(could not write)", std::regex_constants::icase),
        std::regex(R"(permission denied)", std::regex_constants::icase),
        std::regex(R"(detached head)", std::regex_constants::icase),
    };

    for (const auto& pattern : failurePatterns) {
        if (std::regex_search(lowerOutput, pattern)) {
            isCommitFailed = true;
            break;
        }
    }

    if (isCommitFailed) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitCommit] git commit failed: %{public}s", output.c_str());
        return output;
    }

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitCommit] cmmit success: %{public}s {public}s",
        isAmend ? "with --amend" : "", isSignOff ? "with --signOff" : "");
    return output;
}

static napi_value SysCallCommitSync(napi_env env, napi_callback_info info)
{
    size_t argc = 5;
    napi_value argv[5];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    // 获取repoPath
    char repoPath[1024] = {0};
    size_t pathLen = 1024;
    if (napi_ok != napi_get_value_string_utf8(env, argv[0], repoPath, sizeof(repoPath), &pathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallCommitSync] get repoPath failed");
        return nullptr;
    }

    // 获取commitMsg
    char messageBuf[4096] = {0};
    size_t messageLen = 4096;
    if (napi_ok != napi_get_value_string_utf8(env, argv[1], messageBuf, sizeof(messageBuf), &messageLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallCommitSync] get commit message failed");
        return nullptr;
    }
    std::string message(messageBuf, messageLen);

    // 获取signOffMassage
    std::string signOffMessage = "";
    if (argc >= 3) {
        napi_valuetype valueType;
        if (napi_ok == napi_typeof(env, argv[2], &valueType) && valueType == napi_string) {
            char signOffBuf[1024] = {0};
            size_t signOffLen = 1024;
            if (napi_ok == napi_get_value_string_utf8(env, argv[2], signOffBuf, sizeof(signOffBuf), &signOffLen)) {
                signOffMessage = std::string(signOffBuf, signOffLen);
            }
        }
    }

    // 获取isSignOff
    bool isSignOff = false;
    if (argc >= 4) {
        napi_valuetype valueType;
        if (napi_ok == napi_typeof(env, argv[3], &valueType) && valueType == napi_boolean) {
            napi_get_value_bool(env, argv[3], &isSignOff);
        }
    }

    // 获取isAmend
    bool isAmend = false;
    if (argc >= 5) {
        napi_valuetype valueType;
        if (napi_ok == napi_typeof(env, argv[4], &valueType) && valueType == napi_boolean) {
            napi_get_value_bool(env, argv[4], &isAmend);
        }
    }

    // 调用GitCommit
    try {
        std::string result = GitCommit(std::string(repoPath), message, signOffMessage, isSignOff, isAmend);
        
        napi_value ret;
        napi_create_string_utf8(env, result.c_str(), result.length(), &ret);
        return ret;
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallCommitSync] Exception: %{public}s", e.what());
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }
}

static bool GitIsUnMerge(const std::string& repoPath)
{
    std::string cmd = "git ls-files -u";
    std::string output;
    int ret = ExecCmd(cmd, repoPath, output);
    if (ret != 0){
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitIsUnMerge] ExecCmd failed: %{public}s", output.c_str());
        return false;
    }
    return !output.empty() && output.find_first_not_of(" \t\n\r") != std::string::npos;
}

static napi_value SysCallIsUnMergeSync(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    if (status != napi_ok || argc < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallIsUnMergeSync] Invalid arguments count");
        return nullptr;
    }

    // 获取repoPath
    char repoPathBuf[1024] = {0};
    size_t pathLen = 1024;
    status = napi_get_value_string_utf8(env, argv[0], repoPathBuf, sizeof(repoPathBuf), &pathLen);
    if (status != napi_ok || pathLen == 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallIsUnMergeSync] Failed to get repoPath");
        return nullptr;
    }
    std::string repoPath(repoPathBuf, pathLen);

    bool isUnMerge = GitIsUnMerge(repoPath);
    
    // 构建返回
    napi_value result;
    status = napi_get_boolean(env, isUnMerge, &result);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallIsUnMergeSync] Failed to create boolean result");
        return nullptr;
    }
    return result;
}

static bool IsFileUnMerge(const std::string& repoPath, const std::string& filePath)
{
    if (repoPath.empty() || filePath.empty()) {
        return false;
    }
    
    // 构建命令
    std::string cmd = "git ls-files -u --stage | awk '$3 ~ /^[123]$/ && $4 == \"" + filePath + "\" {print $0}'";
    std::string output;
    int ret = ExecCmd(cmd, repoPath, output);
    if(ret != 0) {
        return false;
    }
    return !output.empty() && output.find_first_not_of(" \t\n\r") != std::string::npos;
}

static std::vector<std::string> GitFindUnMerge(const std::string& repoPath)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitFindUnMerge] repoPath is empty");
        return {};
    }

    // 构建命令
    std::string cmd = "git ls-files -u";
    std::string output;
    int ret = ExecCmd(cmd, repoPath, output);
    if(ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitFindUnMerge] Failed to execute command");
        return {};
    }
    if (output.empty() || output.find_first_not_of(" \t\n\r") == std::string::npos) {
        return {};
    }

    std::vector<std::string> unmergedFiles;
    std::istringstream iss(output);
    std::string line;

    while (std::getline(iss, line)) {
        line.erase(0, line.find_first_not_of(" \t"));
        line.erase(line.find_last_not_of(" \t") + 1);
        
        if(line.empty()) {
            continue;
        }
        size_t lastSapce = line.find_last_of(" \t");
        if (lastSapce == std::string::npos) {
            continue;
        }

        std::string filePath = line.substr(lastSapce + 1);
        if (!filePath.empty()) {
            unmergedFiles.push_back(filePath);
        }
    }

    std::sort(unmergedFiles.begin(), unmergedFiles.end());
    auto it = std::unique(unmergedFiles.begin(), unmergedFiles.end());
    unmergedFiles.erase(it, unmergedFiles.end());
    OH_LOG_Print(LOG_APP, LOG_INFO, 1, "GitNext", "[GitFindUnMerge] unmergedFiles size: %{public}lu", unmergedFiles.size());
    
    return unmergedFiles;
}

static napi_value SysCallFindUnMergeSync(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    if (status != napi_ok || argc < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallFindUnMergeSync] Invalid arguments count");
        return nullptr;
    }

    // 获取repoPath
    char repoPathBuf[1024] = {0};
    size_t pathLen = 1024;
    if (napi_ok != napi_get_value_string_utf8(env, argv[0], repoPathBuf, sizeof(repoPathBuf), &pathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallFindUnMergeSync] Failed to get repoPath");
        return nullptr;
    }
    std::string repoPath(repoPathBuf, pathLen);

    // 调用核心函数
    std::vector<std::string> unmergedFiles;
    try {
        unmergedFiles = GitFindUnMerge(repoPath);
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallFindUnMergeSync] Exception: %{public}s", e.what());
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }

    // 返回结果
    napi_value result;
    napi_create_array(env, &result);
    for (size_t i = 0; i < unmergedFiles.size(); ++i) {
        napi_value item;
        napi_create_string_utf8(env, unmergedFiles[i].c_str(), unmergedFiles[i].length(), &item);
        napi_set_element(env, result, i, item);
    }
    return result;
}

static std::string JoinStrings(const std::vector<std::string>& vec, const std::string& delim)
{
    if (vec.empty()) {
        return "";
    }
    std::ostringstream oss;
    auto it = vec.begin();
    oss << *it++;
    while (it != vec.end()) {
        oss << delim << *it++;
    }
    return oss.str();
}

static std::string ParseDiffOutput(const std::string& input)
{
    std::vector<std::string> lines;
    std::string token;
    std::istringstream iss(input);
    
    while (std::getline(iss, token)) {
        if (token.find("@@") != std::string::npos) {
            lines.push_back(token);
        } else if (token.find("delete file mode") != std::string::npos) {
            lines.push_back(token);
        } else if (token.length() > 0 && token[0] == '+' || token[0] == '-' || token[0] == ' ') {
            lines.push_back(token);
        }
    }

    return JoinStrings(lines, "\n");
}

static std::string Trim(const std::string& str)
{
    if (str.empty()) {
        return "";
    }
    
    const std::string whiteSpace = " \t\n\r\f\v";
    std::string::size_type start = str.find_first_not_of(whiteSpace);
    std::string::size_type end = str.find_last_not_of(whiteSpace);
    if (start == std::string::npos || end == std::string::npos) {
        return "";
    }
    return str.substr(start, end - start + 1);
}

static std::string GitShowDiff(const std::string& repoPath, const std::string& filePath, const int level)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitShowDiff] repoPath is empty");
        return "";
    }
    if (filePath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitShowDiff] filePath is empty");
        return "";
    }

    // 判断是否为冲突文件
    if (IsFileUnMerge(repoPath, filePath)) {
        std::string cmd = "nice git diff --textconv -p --no-color -U" + std::to_string(level) +
                        " :1:" + filePath + " :2:" + filePath;
        std::string result;
        int ret = ExecCmd(cmd, repoPath, result);
        if (ret == 0) {
            return ParseDiffOutput(result);
        }
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitShowDiff] ExecCmd failed, cmd:%{public}s, ret:%{public}d", cmd.c_str(), ret);
        return "";
    }

    // 尝试diff-files
    std::string diffCmd = "nice git diff-files --textconv -p --no-color -U" + std::to_string(level) + " -- '" + filePath + "'";
    std::string outputDiffFiles;
    int ret = ExecCmd(diffCmd, repoPath, outputDiffFiles);
    if (ret == 0 && !outputDiffFiles.empty()) {
        return ParseDiffOutput(outputDiffFiles);
    }
    
    // 尝试diff-index
    std::string revCmd = "git rev-parse HEAD";
    std::string headHash;
    ret = ExecCmd(revCmd, repoPath, headHash);
    if (ret != 0 || headHash.empty()) {
        return "";
    }
    headHash = Trim(headHash);
    std::string indexCmd = "nice git diff-index --cached --ignore-submodules=dirty --textconv -p --no-color -U"
                        + std::to_string(level) + " " + headHash + " -- '" + filePath + "'";
    std::string outputDiffIndex;
    ret = ExecCmd(indexCmd, repoPath, outputDiffIndex);
    if (ret == 0 && !outputDiffIndex.empty()) {
        return ParseDiffOutput(outputDiffIndex);
    }

    return "";
}

static napi_value SysCallShowDiffSync(napi_env env, napi_callback_info info)
{
    size_t argc = 3;
    napi_value args[3];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    // 获取 repoPath
    char repoPathBuf[1024] = {0};
    size_t repoPathLen = 1024;
    if (napi_ok != napi_get_value_string_utf8(env, args[0], repoPathBuf, repoPathLen, &repoPathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "Failed to get repoPath");
        return nullptr;
    }
    std::string repoPath(repoPathBuf, repoPathLen);

    // 获取 filePath
    char filePathBuf[1024] = {0};
    size_t filePathLen = 1024;
    if (napi_ok != napi_get_value_string_utf8(env, args[1], filePathBuf, filePathLen, &filePathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "Failed to get filePath");
        return nullptr;
    }
    std::string filePath(filePathBuf, filePathLen);

    // 获取level
    int level = 3;
    if (argc >= 3) {
        napi_valuetype type;
        if (napi_ok == napi_typeof(env, args[2], &type) && type == napi_number) {
            double levelDouble;
            napi_get_value_double(env, args[2], &levelDouble);
            level = static_cast<int>(levelDouble);
            if (level < 0) level = 0;
        }
    }

    try {
        std::string result = GitShowDiff(repoPath, filePath, level);

        napi_value ret;
        napi_create_string_utf8(env, result.c_str(), result.size(), &ret);
        return ret;
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "Exception: %{public}s", e.what());
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }
}

static std::string TryRestoreWithRetry(const std::string& repoPath, const std::string& filePath, int maxRetries = 2)
{
    std::string restoreCmd = "git restore --staged " + filePath;
    std::string output = "";
    int attempt = 0;

    while (attempt <= maxRetries) {
        ++attempt;
        int ret = ExecCmd(restoreCmd, repoPath, output);
        if (ret == 0) {
            return ""; // 成功返回空字符串
        }
        if (output.find("index.lock") != std::string::npos) {
            const std::string lockPath = repoPath + "/.git/index.lock";
            std::string removeLockCmd = "rm -f " + lockPath;
            ExecCmd(removeLockCmd, repoPath, output);
        }

        if (attempt < maxRetries + 1) {
            int delayMs = 50 * (1 << attempt);
            std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
        }
    }
    
    // 返回错误信息
    return "failed to restore '" + filePath + "' error: " + output;
}

static std::string GitRestore(const std::string& repoPath, const std::vector<std::string>& fileList)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitRestore] repoPath is empty");
        return "repository path is empty";
    }
    
    if (fileList.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitRestore] fileList is empty");
        return "file list is empty";
    }

    std::string errorMessages;
    bool hasErrors = false;

    for (const auto& filePath : fileList) {
        if (filePath.empty()) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitRestore] filePath is empty");
            errorMessages += "empty file path in list\n";
            hasErrors = true;
            continue;
        }
        
        std::string result = TryRestoreWithRetry(repoPath, filePath, 2);
        if (!result.empty()) {
            errorMessages += result + "\n";
            hasErrors = true;
        }
    }
    
    if (hasErrors) {
        return errorMessages;
    }
    
    return "";
}

static napi_value SysCallRestoreSync(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value argv[2];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    // 获取repoPath
    char path[1024] = {0};
    size_t pathLen = 1024;
    if (napi_ok != napi_get_value_string_utf8(env, argv[0], path, sizeof(path), &pathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallRestoreSync] get repoPath failed");
        return nullptr;
    }

    // 获取fileList
    napi_value fileListArg = argv[1];
    uint32_t fileListLength = 0;
    if (napi_ok != napi_get_array_length(env, fileListArg, &fileListLength)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallRestoreSync] get fileList length failed");
        return nullptr;
    }

    std::vector<std::string> fileList;
    fileList.reserve(fileListLength);

    for (uint32_t i = 0; i < fileListLength; ++i) {
        napi_value item;
        if (napi_ok != napi_get_element(env, fileListArg, i, &item)) {
            continue;
        }

        char filePath[1024] = {0};
        size_t filePathLen = 1024;
        if (napi_ok != napi_get_value_string_utf8(env, item, filePath, sizeof(filePath), &filePathLen)) {
            continue;
        }
        fileList.emplace_back(filePath);
    }

    std::string result;
    try {
        result = GitRestore(std::string(path), fileList);
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallRestoreSync] Exception: %{public}s", e.what());
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }

    // 创建并返回结果字符串
    napi_value resultValue;
    if (napi_ok != napi_create_string_utf8(env, result.c_str(), result.length(), &resultValue)) {
        return nullptr;
    }

    return resultValue;
}

struct CommitInfo {
    std::string commit_hash;
    std::string author;
    std::string date;
    std::string message;
};

static std::vector<std::string> SplitString(const std::string& str, char delimiter)
{
    std::vector<std::string> result;
    std::stringstream ss(str);
    std::string item;

    while (std::getline(ss, item, delimiter)) {
        item.erase(0, item.find_first_not_of(" \t\n\r\f\v"));
        item.erase(item.find_last_not_of(" \t\n\r\f\v") + 1);
        result.push_back(item);
    }

    return result;
}

static void GitGetRecentCommitStream(const std::string& repoPath, std::function<void(const CommitInfo&)> callback) 
{
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRecentCommitStream] Starting to get recent commit stream");

    std::string cmd = "git log --pretty=format:'%H|%an|%ad|%s' "
                      "--date=iso --max-count=10 "
                      "--patch --unified=3 --no-merges --no-color 2>&1";
                    
    std::string currentHash = "";
    std::string currentAuthor = "";
    std::string currentDate = "";
    std::string currentTitle = "";
    std::string currentDiffContent = "";
    bool inDiffSection = false;

    auto lineCallback = [&](const std::string& line) {
        if (line == "[EOF]") {
            OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRecentCommitStream] [EOF] reached");
            return;
        }
        if (line.find("sh: cat:") != std::string::npos ||
            line.find("No such file or directory") != std::string::npos ||
            line.find("fatal:") != std::string::npos ||
            line.find("error:") != std::string::npos) {
            OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRecentCommitStream] Filtered error line: %{public}s", line.c_str());
            return;
        }
        
        std::string trimmed = line;
        if (!trimmed.empty() && trimmed.back() == '\n') {
            trimmed.pop_back();
        }
        if (trimmed.empty()) {
            return;
        }

        if (trimmed.find('|') != std::string::npos) {
            std::vector<std::string> parts = SplitString(trimmed, '|');
            if (parts.size() < 4) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRecentCommitStream] Invalid commit info: %{public}s", trimmed.c_str());
                return;
            }
            const std::string& hash = parts[0];
            const std::string& author = parts[1];
            const std::string& date = parts[2];
            const std::string& title = parts[3];

            if (hash.length() != 40) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRecentCommitStream] Invalid hash: %{public}s", hash.c_str());
                return;
            }

            if (hash.find_first_not_of("0123456789abcdefABCDEF") != std::string::npos) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRecentCommitStream] Invalid hash: %{public}s", hash.c_str());
                return;
            }

            if (!currentHash.empty()) {
                CommitInfo info = {currentHash, currentAuthor, currentDate, ""};
                info.message = currentTitle + "\n\n" + currentDiffContent;
                callback(info);
            }

            currentHash = hash;
            currentAuthor = author;
            currentDate = date;
            currentTitle = title;
            currentDiffContent = "";
            inDiffSection = true;
            return;
        }

        if (inDiffSection) {
            if (trimmed.find("index ") == 0 ||
                trimmed.find("new file") == 0 ||
                trimmed.find("deleted file") == 0 ||
                trimmed.find("mode ") == 0 ||
                trimmed.find("rename from") == 0 ||
                trimmed.find("rename to") == 0) {
                    return;
            }
            if (trimmed.find("diff --git") == 0) {
                if (!currentDiffContent.empty()) {
                    currentDiffContent += "\n";
                }
                currentDiffContent += "Modefied file: " + trimmed.substr(10);
                return;
            }
            if (trimmed.find("@@ ") == 0) {
                if (!currentDiffContent.empty()) {
                    currentDiffContent += "\n";
                }
                currentDiffContent += trimmed;
                return;
            }
            if (!trimmed.empty() && (trimmed[0] == '+' || trimmed[0] == '-')) {
                if (!currentDiffContent.empty()) {
                    currentDiffContent += "\n";
                }
                currentDiffContent += trimmed;
                return;
            }
        }
    };

    int ret = ExecCmd(cmd, repoPath, lineCallback);
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRecentCommitStream] Failed to get recent commit %{public}d", ret);
        return;
    }

    if (!currentHash.empty()) {
        CommitInfo info = {currentHash, currentAuthor, currentDate, currentTitle};
        info.message = currentTitle + "\n\n" + currentDiffContent;
        callback(info);
    }
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRecentCommitStream] Successfully getting recent commit stream");
}

static std::vector<CommitInfo> GitGetRecentCommits(const std::string& repoPath)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRecentCommits] Invalid repo path");
        return {};
    }

    std::vector<CommitInfo> commits;
    GitGetRecentCommitStream(repoPath, [&](const CommitInfo& commit) {
        commits.push_back(commit);
    });

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRecentCommits] Retrieved %{public}zu commits", commits.size());
    return commits;
}

static napi_value SysCallGetRecentCommitsSync(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    char repoPathBuf[1024] = {0};
    size_t repoPathLen = 1024;

    if (napi_ok != napi_get_value_string_utf8(env, argv[0], repoPathBuf, sizeof(repoPathBuf), &repoPathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRecentCommitsSync] Failed to get repo path");
        return nullptr;
    }

    std::string repoPath(repoPathBuf, repoPathLen);
    try {
        auto commits = GitGetRecentCommits(repoPath);
        if (commits.empty()) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRecentCommitsSync] Failed to get recent commits");
            napi_value result = nullptr;
            napi_get_null(env, &result);
            return result;
        }

        napi_value array = nullptr;
        napi_create_array(env, &array);

        for (size_t i = 0; i < commits.size(); ++i) {
            const auto& commit = commits[i];

            napi_value commitObj = nullptr;
            napi_create_object(env, &commitObj);

            napi_value hashKey;
            napi_create_string_utf8(env, "hash", NAPI_AUTO_LENGTH, &hashKey);
            napi_value hashValue = nullptr;
            napi_status hashStatus = napi_create_string_utf8(env, commit.commit_hash.c_str(), NAPI_AUTO_LENGTH, &hashValue);
            if (hashStatus != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRecentCommitsSync] Failed to create hash");
                return nullptr;
            }
            napi_set_property(env, commitObj, hashKey, hashValue);
 
            napi_value authorKey;
            napi_create_string_utf8(env, "author", NAPI_AUTO_LENGTH, &authorKey);
            napi_value authorValue = nullptr;
            napi_status authorStatus = napi_create_string_utf8(env, commit.author.c_str(), NAPI_AUTO_LENGTH, &authorValue);
            if (authorStatus != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRecentCommitsSync] Failed to create author");
                return nullptr;
            }
            napi_set_property(env, commitObj, authorKey, authorValue);

            napi_value dateKey;
            napi_create_string_utf8(env, "date", NAPI_AUTO_LENGTH, &dateKey);
            napi_value dateValue = nullptr;
            napi_status dateStatus = napi_create_string_utf8(env, commit.date.c_str(), NAPI_AUTO_LENGTH, &dateValue);
            if (dateStatus != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRecentCommitsSync] Failed to create date");
                return nullptr;
            }
            napi_set_property(env, commitObj, dateKey, dateValue);

            napi_value msgKey = nullptr;
            napi_create_string_utf8(env, "message", NAPI_AUTO_LENGTH, &msgKey);
            napi_value msgValue = nullptr;
            napi_status msgStatus = napi_create_string_utf8(env, commit.message.c_str(), NAPI_AUTO_LENGTH, &msgValue);
            if (msgStatus != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRecentCommitsSync] Failed to create message");
                return nullptr;
            }
            napi_set_property(env, commitObj, msgKey, msgValue);

            napi_set_element(env, array, i, commitObj);
        }
        return array;
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRecentCommitsSync] Exception: %{public}s", e.what());
        napi_value result = nullptr;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &result);
        napi_throw(env, result);
        return nullptr;
    }
}

static std::vector<std::string> GitGetLocalBranches(const std::string& repoPath)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetLocalBranches] Invalid repo path");
        return {};
    }

    std::string cmd = "git for-each-ref --sort=-taggerdate --format=\"%(refname)\" refs/heads";
    std::string result = "";
    int ret = ExecCmd(cmd.c_str(), repoPath, result);
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetLocalBranches] Failed to get local branches, ret: %{public}d", ret);
        return {};
    }

    if (result.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetLocalBranches] Failed to get local branches");
        return {};
    }

    std::vector<std::string> branches;
    std::istringstream iss(result);
    std::string branch;
    while (std::getline(iss, branch, '\n')) {
        branch = Trim(branch);
        if (branch.empty()) {
            continue;
        }
        const std::string prefix = "refs/heads/";
        int prefixLen = static_cast<int>(prefix.length());
        if (branch.length() < prefixLen) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetLocalBranches] Invalid too short branch: %{public}s", branch.c_str());
            continue;
        }
        if (branch.compare(0, prefixLen, prefix) == 0) {
            std::string branchName = branch.substr(prefixLen);
            if (!branchName.empty()) {
                branches.push_back(branchName);
            }
        } else {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetLocalBranches] unref format branch: %{public}s", branch.c_str());
        }   
    }
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetLocalBranches] Retrieved %{public}zu branches", branches.size());
    return branches;
}

static napi_value SysCallGetLocalBranchesSync(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    char repoPathBuf[1024] = {0};
    size_t repoPathLen = 1024;

    if (napi_ok != napi_get_value_string_utf8(env, argv[0], repoPathBuf, sizeof(repoPathBuf), &repoPathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetLocalBranchesSync] Failed to get repo path");
        return nullptr;
    }

    std::string repoPath = std::string(repoPathBuf, repoPathLen);
    try {
        auto branches = GitGetLocalBranches(repoPath);
        napi_value array;

        napi_status status = napi_create_array(env, &array);
        if (status != napi_ok) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetLocalBranchesSync] Failed to create array");
            return nullptr;
        }

        for (size_t i = 0; i < branches.size(); ++i) {
            napi_value retStr;
            status = napi_create_string_utf8(env, branches[i].c_str(), NAPI_AUTO_LENGTH, &retStr);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetLocalBranchesSync] Failed to create string");
                return nullptr;
            }
            status = napi_set_element(env, array, i, retStr);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetLocalBranchesSync] Failed to set element");
                return nullptr;
            }
        }
        return array;
    } catch (const std::exception& e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetLocalBranchesSync] Exception: %{public}s", e.what());
        napi_value error = nullptr;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }
}

static bool IsStartWith(const std::string& str, const std::string& prefix)
{
    if (str.length() < prefix.length()) {
        return false;
    }
    return str.compare(0, prefix.length(), prefix) == 0;
}

size_t SafeAccumulate(const std::vector<std::string>& vec)
{
    size_t ret = 0;
    for (const auto& str : vec) {
        ret += str.length();
    }
    return ret;
}

static std::vector<std::vector<std::string>> GitGetRemoteBranches(const std::string& repoPath)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRemoteBranches] Invalid repo path");
        return {};
    }
    
    std::vector<std::string> remoteNames;
    std::string remotesCmd = "git remote";
    std::string remotesResult;
    int ret = ExecCmd(remotesCmd, repoPath, remotesResult);
    
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_WARN, 1, "GitNext", 
            "[GitGetRemoteBranches] Failed to get remotes, ret: %{public}d", ret);
        return {};
    }
    
    std::istringstream remotesStream(remotesResult);
    std::string remoteName;
    while (std::getline(remotesStream, remoteName)) {
        remoteName = Trim(remoteName);
        if (!remoteName.empty()) {
            remoteNames.push_back(remoteName);
        }
    }
    
    if (remoteNames.empty()) {
        OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", 
            "[GitGetRemoteBranches] No remotes found");
        return {};
    }
    
    std::vector<std::vector<std::string>> retVec;
    
    std::string cmd = "git for-each-ref --format=\"%(refname)\" refs/remotes/";
    std::string result;
    ret = ExecCmd(cmd, repoPath, result);
    
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", 
            "[GitGetRemoteBranches] Failed to get remote branches, ret: %{public}d", ret);
        for (const auto& remote : remoteNames) {
            retVec.push_back({remote});
        }
        return retVec;
    }
    
    std::unordered_map<std::string, std::vector<std::string>> remoteBranchesMap;
    
    for (const auto& remote : remoteNames) {
        remoteBranchesMap[remote] = {};
    }
    
    std::istringstream iss(result);
    std::string ref;
    while (std::getline(iss, ref)) {
        ref = Trim(ref);
        if (ref.empty()) continue;
        
        if (ref.find("refs/remotes/") == 0) {
            std::string path = ref.substr(13);
            size_t slashPos = path.find('/');
            if (slashPos != std::string::npos) {
                std::string remoteName = path.substr(0, slashPos);
                std::string branchName = path.substr(slashPos + 1);
                
                if (remoteBranchesMap.find(remoteName) != remoteBranchesMap.end()) {
                    remoteBranchesMap[remoteName].push_back(branchName);
                }
            }
        }
    }
    for (const auto& remote : remoteNames) {
        std::vector<std::string> item;
        item.push_back(remote);
        
        const auto& branches = remoteBranchesMap[remote];
        item.insert(item.end(), branches.begin(), branches.end());
        
        retVec.push_back(item);
    }
    
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", 
        "[GitGetRemoteBranches] Retrieved %{public}zu remote branches for %{public}zu remotes", 
        result.empty() ? 0 : std::count(result.begin(), result.end(), '\n') + 1, 
        retVec.size());
    
    return retVec;
}

static napi_value SysCallGetRemoteBranchesSync(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    char repoPathBuf[1024] = {0};
    size_t repoPathLen = 1024;

    if (napi_ok != napi_get_value_string_utf8(env, argv[0], repoPathBuf, sizeof(repoPathBuf), &repoPathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to get repo path");
        return nullptr;
    }

    std::string repoPath = std::string(repoPathBuf, repoPathLen);
    try {
        auto branches = GitGetRemoteBranches(repoPath);
        const size_t MAX_BRANCHES = 1000;
        if (branches.size() > MAX_BRANCHES) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Too many branches: %{public}zu", branches.size());
            branches.resize(MAX_BRANCHES);
        }
        napi_value array = nullptr;

        napi_status status = napi_create_array(env, &array);
        if (status != napi_ok) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to create array");
            return nullptr;
        }

        size_t successCnt = 0;
        for (size_t i = 0; i < branches.size(); ++i) {
            const auto & branch = branches[i];
            if (branch.empty()) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Invalid branch");
                continue;
            }

            napi_value remoteArray = nullptr;
            status = napi_create_array(env, &remoteArray);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to create array");
                return nullptr;
            }
            
            const std::string &remoteName = branch[0];
            if (remoteName.empty()) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Invalid remote name");
                continue;   
            }
            napi_value remoteNameStr = nullptr;
            status = napi_create_string_utf8(env, remoteName.c_str(), remoteName.length(), &remoteNameStr);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to create string");
                return nullptr;
            }
            status = napi_set_element(env, remoteArray, 0, remoteNameStr);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to set element");
                return nullptr;
            }

            for (size_t j = 1; j < branch.size(); ++j) {
                const std::string &branchName = branch[j];
                if (branchName.empty()) {
                    OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Invalid branch name");
                    continue;
                }
                napi_value branchNameStr = nullptr;
                status = napi_create_string_utf8(env, branchName.c_str(), branchName.length(), &branchNameStr);
                if (status != napi_ok) {
                    OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to create string");
                    return nullptr;
                }
                status = napi_set_element(env, remoteArray, j, branchNameStr);
                if (status != napi_ok) {
                    OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to set element");
                    return nullptr;
                }
            }
            status = napi_set_element(env, array, successCnt++, remoteArray);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] Failed to set element");
                return nullptr;
            }
        }
        return array;
    } catch (const std::exception &e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetRemoteBranchesSync] %{public}s", e.what());
        napi_value error = nullptr;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }
}

static std::vector<std::string> GitGetAllTags(const std::string &repoPath)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetAllTags] Invalid repo path");
        return {};
    }
    std::string cmd = "git for-each-ref --sort=-taggerdate --format=\"%(refname)\" refs/tags";
    std::string result = "";
    int ret = ExecCmd(cmd, repoPath, result);
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetAllTags] Failed to execute command: %{public}s", cmd.c_str());
        return {};
    }
    if (result.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetAllTags] No tags found");
        return {};
    }
    std::istringstream iss(result);
    std::string tag;
    std::vector<std::string> tags;

    while (std::getline(iss, tag)) {
        tag = Trim(tag);
        if (tag.empty()) {
            continue;
        }
        const std::string tagPrefix = "refs/tags/";
        int prefixLen = static_cast<int>(tagPrefix.length());
        if (tag.length() < prefixLen) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetAllTags] Invalid tag: %{public}s", tag.c_str());
            continue;
        }
        if (tag.compare(0, prefixLen, tagPrefix) == 0) {
            std::string tagName = tag.substr(prefixLen);
            if (!tagName.empty()) {
                tags.push_back(tagName);
            }
        } else {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetAllTags] Invalid tag: %{public}s", tag.c_str());
        }       
    }
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetAllTags] Retrieved %{public}zu tags", tags.size());
    return tags;
}

static napi_value SysCallGetAllTagSync(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    char repoPathBuf[1024] = {0};
    size_t repoPathLen = 1024;

    if (napi_ok != napi_get_value_string_utf8(env, argv[0], repoPathBuf, sizeof(repoPathBuf), &repoPathLen)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetAllTagSync] Failed to get repo path");
        return nullptr;
    }

    std::string repoPath = std::string(repoPathBuf, repoPathLen);
    try {
        auto tags = GitGetAllTags(repoPath);

        napi_value array = nullptr;
        napi_status status = napi_create_array(env, &array);
        if (status != napi_ok) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetAllTagSync] Failed to create array");
            return nullptr;
        }

        for (size_t i = 0; i < tags.size(); ++i) {
            napi_value tag = nullptr;
            status = napi_create_string_utf8(env, tags[i].c_str(), tags[i].length(), &tag);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetAllTagSync] Failed to create string");
                return nullptr;
            }
            status = napi_set_element(env, array, i, tag);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetAllTagSync] Failed to set element");
                return nullptr;
            }
        }
        return array;
    } catch (const std::exception &e) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SysCallGetAllTagSync] %{public}s", e.what());
        napi_value error = nullptr;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return error;
    }
}

struct RemoteInfo {
    std::string name = "";
    std::string fetchUrl = "";
    std::string pushUrl = "";
    bool isDefault = false;

    RemoteInfo() = default;
    RemoteInfo(const std::string &name, const std::string &fetchUrl, const std::string &pushUrl)
        :name(name), fetchUrl(fetchUrl), pushUrl(pushUrl) {}
};

static std::vector<RemoteInfo> GitGetRemoteInfo(const std::string &repoPath)
{
    if (repoPath.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRemoteInfo] Invalid repo path");
        return {};
    }
    std::string cmd = "git remote -v";
    std::string result = "";
    int ret = ExecCmd(cmd, repoPath, result);
    if (ret != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRemoteInfo] Failed to execute command: %{public}s", cmd.c_str());
        return {};
    }
    if (result.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRemoteInfo] No remote info found");
        return {};
    }
    std::stringstream ss(result);
    std::string remote;
    std::vector<RemoteInfo> remoteInfos;

    const std::regex remoteRegex(R"(^(\S+)\s+(https?://[^ ]+)\s+\((fetch|push)\)$)");
    while (std::getline(ss, remote)) {
        remote = Trim(remote);
        if (remote.empty()) {
            continue;
        }
        std::smatch match;
        if (!std::regex_match(remote, match, remoteRegex)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRemoteInfo] Invalid remote info: %{public}s", remote.c_str());
            continue;
        }
        if (match.size() != 4) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRemoteInfo] Invalid remote info: %{public}s", remote.c_str());
            continue;
        }
        std::string name = match[1];
        std::string fetchUrl = match[2];
        std::string type = match[3];

        auto item = std::find_if(remoteInfos.begin(), remoteInfos.end(), [&name](const RemoteInfo &info) {
            return info.name == name;
        });
        if (item == remoteInfos.end()) {
            RemoteInfo info(name, fetchUrl, "");
            if (type == "fetch") {
                info.fetchUrl = fetchUrl;
            } else if (type == "push") {
                info.pushUrl = fetchUrl;
            }
        } else {
            if (type == "fetch") {
                item->fetchUrl = fetchUrl;
            } else if (type == "push") {
                item->pushUrl = fetchUrl;
            }
        }
    }

    cmd = "cd \"" + repoPath + "\" && git config --get remote.default";
    std::string defaultRemote = "";
    ret = ExecCmd(cmd, repoPath, defaultRemote);
    if (ret == 0 && !defaultRemote.empty()) {
        OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRemoteInfo] Default remote: %{public}s", defaultRemote.c_str());
        for (auto &info : remoteInfos) {
            if (info.name == defaultRemote) {
                info.isDefault = true;
                break;
            }
        }
    } else {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[GitGetRemoteInfo] Failed to get default remote");
    }

    if (defaultRemote.empty()) {
        OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRemoteInfo] No default remote found");
        for (auto &info : remoteInfos) {
            if (info.name == "origin") {
                info.isDefault = true;
                break;  
            }
        }
    }
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 1, "GitNext", "[GitGetRemoteInfo] Retrieved %{public}zu remote infos", remoteInfos.size());
    return remoteInfos;
}

static napi_value SysCallGetRemoteInfoSync(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    char pathBuf[1024] = {0};
    size_t pathLen = 1024;

    if (napi_get_value_string_utf8(env, argv[0], pathBuf, sizeof(pathBuf), &pathLen) != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SyscallGetRemoteInfoSync] Failed to get repo path");
        return nullptr;
    }

    std::vector<RemoteInfo> remotes;
    try {
        remotes = GitGetRemoteInfo(std::string(pathBuf));
    } catch (const std::exception &e) {    
        OH_LOG_Print(LOG_APP, LOG_ERROR, 1, "GitNext", "[SyscallGetRemoteInfoSync] Execption: %{public}s", e.what());
        napi_value error;
        napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &error);
        napi_throw(env, error);
        return nullptr;
    }

    napi_value remoteObj = nullptr;
    napi_status status = napi_create_object(env, &remoteObj);

    napi_value remoteArray = nullptr;
    status = napi_create_array_with_length(env, remotes.size(), &remoteArray);

    for (size_t i = 0; i < remotes.size(); ++i) {
        napi_value remoteInfo = nullptr;
        status = napi_create_object(env, &remoteInfo);

        napi_value nameKey = nullptr;
        status = napi_create_string_utf8(env, "name", NAPI_AUTO_LENGTH, &nameKey);
        napi_value nameValue = nullptr;
        status = napi_create_string_utf8(env, remotes[i].name.c_str(), NAPI_AUTO_LENGTH, &nameValue);
        status = napi_set_property(env, remoteInfo, nameKey, nameValue);
        
        napi_value fetchUrlKey = nullptr;
        status = napi_create_string_utf8(env, "fetchUrl", NAPI_AUTO_LENGTH, &fetchUrlKey);
        napi_value fetchUrlValue = nullptr;
        if (!remotes[i].fetchUrl.empty()) {
            status = napi_create_string_utf8(env, remotes[i].fetchUrl.c_str(), NAPI_AUTO_LENGTH, &fetchUrlValue);   
        } else {
            status = napi_get_null(env, &fetchUrlValue);
        }
        status = napi_set_property(env, remoteInfo, fetchUrlKey, fetchUrlValue);

        napi_value pushUrlKey = nullptr;
        status = napi_create_string_utf8(env, "pushUrl", NAPI_AUTO_LENGTH, &pushUrlKey);
        napi_value pushUrlValue = nullptr;
        if (!remotes[i].pushUrl.empty()) {
            status = napi_create_string_utf8(env, remotes[i].pushUrl.c_str(), NAPI_AUTO_LENGTH, &pushUrlValue);   
        } else {
            status = napi_get_null(env, &pushUrlValue);
        }
        status = napi_set_property(env, remoteInfo, pushUrlKey, pushUrlValue);

        napi_value isDefaultKey = nullptr;
        status = napi_create_string_utf8(env, "isDefault", NAPI_AUTO_LENGTH, &isDefaultKey);
        napi_value isDefaultValue = nullptr;
        status = napi_get_boolean(env, remotes[i].isDefault, &isDefaultValue);
        status = napi_set_property(env, remoteInfo, isDefaultKey, isDefaultValue);

        status = napi_set_element(env, remoteArray, i, remoteInfo);
    }
    napi_value remoteObjKey = nullptr;
    status = napi_create_string_utf8(env, "remote", NAPI_AUTO_LENGTH, &remoteObjKey);
    status = napi_set_property(env, remoteObj, remoteObjKey, remoteArray);
    return remoteObj;
}


EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"set_env", nullptr, SetConfigEnv, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"chmod", nullptr, Chmod, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_sync", nullptr, SysCallSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_async", nullptr, SysCallAsync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_buf", nullptr, SysCallBuf, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_by_line", nullptr, SysCallByLine, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_initConfig_sync", nullptr, SysCallInitConfigSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_rescan_sync", nullptr, SysCallReScanSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_add_sync", nullptr, SysCallAddSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_commit_sync", nullptr, SysCallCommitSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_show_diff_sync", nullptr, SysCallShowDiffSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_get_recent_commit_sync", nullptr, SysCallGetRecentCommitsSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_restore_sync", nullptr, SysCallRestoreSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_is_unmerge_sync", nullptr, SysCallIsUnMergeSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_find_unmerge_sync", nullptr, SysCallFindUnMergeSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_get_local_branches_sync", nullptr, SysCallGetLocalBranchesSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_get_remote_branches_sync", nullptr, SysCallGetRemoteBranchesSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_get_all_tag_sync", nullptr, SysCallGetAllTagSync, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"syscall_get_remote_info_sync", nullptr, SysCallGetRemoteInfoSync, nullptr, nullptr, nullptr, napi_default, nullptr},
    };

    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module gitGuiModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "git_napi",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&gitGuiModule); }
